/**************************************************************************************************
**                                                                                               **
**  文件名称:  dal_input_drv.c                                                                   **
**  版权所有:  CopyRight @ Xiamen Yaxon NetWork CO.LTD. 2017                                     **
**  文件描述:  I/O口传感器输入状态检测                                                           **
**  ===========================================================================================  **
**  创建信息:  | 2017-7-27 | LEON | 创建本模块                                                   **
**  ===========================================================================================  **
**  修改信息:  单击此处添加....                                                                  **
**************************************************************************************************/
#include "dal_include.h"
#include "dal_input_drv.h"
/*************************************************************************************************/
/*                           定义配置参数                                                        */
/*************************************************************************************************/
#define BASETIME             10                                                /* 基准采样时间为10ms */
#define MAX_USER             10                                                /* 一个IO的注册用户数 */

#define PERIOD_SAMPLE        _TICK, BASETIME

/*************************************************************************************************/
/*                           定义模块数据结构                                                    */
/*************************************************************************************************/
typedef struct {
    INT8U          cur_stat;                                                   /* 当前IO状态 */
    INT8U          pre_stat;                                                   /* 前一IO状态 */
    INT8U          flt_stat;                                                   /* 滤波后IO状态 */
    INT8U          ct_users;                                                   /* 一个IO注册用户数 */
    INT32U         ct_flter;                                                   /* 滤波计数器 */
    INPUT_TRIG_E   trg_mode[MAX_USER];                                         /* 触发模式 */
    void         (*c_inform[MAX_USER])(INPUT_PORT_E, INPUT_TRIG_E);            /* 通知函数 */
    void         (*b_inform[MAX_USER])(INPUT_PORT_E, INPUT_TRIG_E);            /* 备份防错 */
} ICB_T;

/*************************************************************************************************/
/*                           定义模块变量                                                        */
/*************************************************************************************************/
static INT8U s_sampletmr;
static ICB_T s_inputdcb[INPUT_PORT_MAX];

/**************************************************************************************************
**  函数名称:  Input_Initiate
**  功能描述:  通用GPIO初始化
**  输入参数:  无
**  输出参数:  无
**  返回参数:  无
**************************************************************************************************/
static void Input_Initiate(INPUT_PORT_E port)
{
    const INPUT_IO_T *pinfo;
    GPIO_InitTypeDef  GPIO_InitStructure;
    
    if (port >= DAL_INPUT_GetIOMax()) {
        return;
    }
    
    pinfo = DAL_INPUT_GetCfgTblInfo(port);
    
    GPIO_InitStructure.GPIO_Pin   = pinfo->pin;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
    
    GPIO_Init((GPIO_TypeDef *)pinfo->gbase, &GPIO_InitStructure);
}

/**************************************************************************************************
**  函数名称:  Input_ReadState
**  功能描述:  读取通用GPIO状态,高电平表示有效
**  输入参数:  port: 输入口编号，见INPUT_IO_E
**  输出参数:  无
**  返回参数:  有效返回TRUE,无效返回false
**************************************************************************************************/
static BOOLEAN Input_ReadState(INPUT_PORT_E port)
{
    const INPUT_IO_T *pinfo;
    
    if (port >= DAL_INPUT_GetIOMax()) {
        return false;
    }
    
    pinfo = DAL_INPUT_GetCfgTblInfo(port);
    
    if (GPIO_ReadInputDataBit((GPIO_TypeDef *)pinfo->gbase, pinfo->pin) == Bit_SET) {
        return TRUE;
    } else {
        return FALSE;
    }
}

/**************************************************************************************************
**  函数名称:  SignalChangeInform
**  功能描述:  信号变化通知
**  输入参数:  port:输入IO口
**  输出参数:  无
**  返回参数:  无
**************************************************************************************************/
static void SignalChangeInform(INPUT_PORT_E port)
{
    INT8U i;
    
    if (s_inputdcb[port].flt_stat != 0) {                                      /* 处理高电平触发 */
        for (i = 0; i < s_inputdcb[port].ct_users; i++) {
            if ((s_inputdcb[port].trg_mode[i] == INPUT_TRIG_POSITIVE) || (s_inputdcb[port].trg_mode[i] == INPUT_TRIG_BOTHSIDE)) {
                SYS_ASSERT((s_inputdcb[port].c_inform[i] != 0), RETURN_VOID);
                SYS_ASSERT((s_inputdcb[port].c_inform[i] == s_inputdcb[port].b_inform[i]), RETURN_VOID);
                s_inputdcb[port].c_inform[i](port, INPUT_TRIG_POSITIVE);
            }
        }
    } else {                                                                   /* 处理低电平触发 */
        for (i = 0; i < s_inputdcb[port].ct_users; i++) {
            if ((s_inputdcb[port].trg_mode[i] == INPUT_TRIG_NEGATIVE) || (s_inputdcb[port].trg_mode[i] == INPUT_TRIG_BOTHSIDE)) {
                SYS_ASSERT((s_inputdcb[port].c_inform[i] != 0), RETURN_VOID);
                SYS_ASSERT((s_inputdcb[port].c_inform[i] == s_inputdcb[port].b_inform[i]), RETURN_VOID);
                s_inputdcb[port].c_inform[i](port, INPUT_TRIG_NEGATIVE);
            }
        }
    }
}

/**************************************************************************************************
**  函数名称:  SampleTmrProc
**  功能描述:  采样周期定时器
**  输入参数:  无
**  输出参数:  无
**  返回参数:  无
**************************************************************************************************/
static void SampleTmrProc(void)
{
    INPUT_PORT_E       index, portname;
    INT32U             filtertime;
    INPUT_IO_T const  *pio;
    
    OSI_StartTimer(s_sampletmr, PERIOD_SAMPLE);
    
    for (index = (INPUT_PORT_E)0; index < DAL_INPUT_GetIOMax(); index++) {
        
        pio = DAL_INPUT_GetCfgTblInfo(index);
        
        portname = pio->port_id;
        
        s_inputdcb[portname].cur_stat = Input_ReadState(portname);             /* 读取当前实时状态 */
    
        if (s_inputdcb[portname].pre_stat != s_inputdcb[portname].cur_stat) {  /* 状态发生变化: 更新状态 */
            s_inputdcb[portname].pre_stat  = s_inputdcb[portname].cur_stat;
            s_inputdcb[portname].ct_flter  = 0;
        } else {                                                               /* 状态没有变化: 开始滤波 */
            if (s_inputdcb[portname].cur_stat != 0) {
                filtertime = ((pio->htime == 0) ? BASETIME : pio->htime);      /* 获取高电平的滤波时间 */
            } else {
                filtertime = ((pio->ltime == 0) ? BASETIME : pio->ltime);      /* 获取低电平的滤波时间 */
            }
            
            if (s_inputdcb[portname].ct_flter < filtertime) {                  /* 累加滤波时间值 */
                s_inputdcb[portname].ct_flter += BASETIME;
                
                if (s_inputdcb[portname].ct_flter >= filtertime) {             /* IO口滤波完成 */
                    if (s_inputdcb[portname].flt_stat != s_inputdcb[portname].cur_stat) { 
                        s_inputdcb[portname].flt_stat  = s_inputdcb[portname].cur_stat;
                        SignalChangeInform(portname);
                    }
                }
            }
        }
    }
}

/**************************************************************************************************
**  函数名称:  DAL_INPUT_Init
**  功能描述:  初始输入驱动模块
**  输入参数:  无
**  输出参数:  无
**  返回参数:  无
**************************************************************************************************/
void DAL_INPUT_Init(void)
{
    INPUT_PORT_E       index, portname;
    INPUT_IO_T const  *pio;
    
    memset(&s_inputdcb, 0, sizeof(s_inputdcb));
    
    for (index = (INPUT_PORT_E)0; index < DAL_INPUT_GetIOMax(); index++) {
        
        pio = DAL_INPUT_GetCfgTblInfo(index); 
        
        portname = pio->port_id;
        
        Input_Initiate(portname);                                              /* 初始化IO状态 */
        
        s_inputdcb[portname].cur_stat = Input_ReadState(portname);
        s_inputdcb[portname].pre_stat = s_inputdcb[portname].cur_stat;
        s_inputdcb[portname].flt_stat = s_inputdcb[portname].cur_stat;
    }

    s_sampletmr = OSI_CreateTimer(SampleTmrProc);
    OSI_StartTimer(s_sampletmr, PERIOD_SAMPLE);
}

/**************************************************************************************************
**  函数名称:  DAL_INPUT_ReadInstantStatus
**  功能描述:  读取当前IO口实时状态(无滤波)
**  输入参数:  port: 输入口编号
**  输出参数:  无
**  返回参数:  有效返回LEVEL_POSITIVE，无效返回LEVEL_NEGATIVE
**************************************************************************************************/
INT8U DAL_INPUT_ReadInstantStatus(INPUT_PORT_E port)
{
    SYS_ASSERT((port < DAL_INPUT_GetIOMax()), LEVEL_NEGATIVE);
    
    if (s_inputdcb[port].cur_stat != 0) {
        return LEVEL_POSITIVE;
    } else {
        return LEVEL_NEGATIVE;
    }
}

/**************************************************************************************************
**  函数名称:  DAL_INPUT_ReadFilterStatus
**  功能描述:  读取滤波后输入口状态
**  输入参数:  port: 输入口编号
**  输出参数:  无
**  返回参数:  有效返回LEVEL_POSITIVE，无效返回LEVEL_NEGATIVE
**************************************************************************************************/
INT8U DAL_INPUT_ReadFilterStatus(INPUT_PORT_E port)
{
    SYS_ASSERT((port < DAL_INPUT_GetIOMax()), LEVEL_NEGATIVE);
    
    if (s_inputdcb[port].flt_stat != 0) {
        return LEVEL_POSITIVE;
    } else {
        return LEVEL_NEGATIVE;
    }
}

/**************************************************************************************************
**  函数名称:  DAL_INPUT_InstallTriggerProc
**  功能描述:  注册输入口状态变化回调通知
**  输入参数:  port: 输入口编号；trigmode: 信号跳变触发模式；informer: 信号变化通知函数
**  输出参数:  无
**  返回参数:  成功返回true，失败返回false
**************************************************************************************************/
BOOLEAN DAL_INPUT_InstallTriggerProc(INPUT_PORT_E port, INPUT_TRIG_E trigmode, void (*informer)(INPUT_PORT_E, INPUT_TRIG_E))
{ 
    INT8U i;
	
	SYS_ASSERT((port < DAL_INPUT_GetIOMax()), RETURN_FALSE);
	SYS_ASSERT((informer != 0), RETURN_FALSE);
    
    for (i = 0; i < MAX_USER; i++) {
        if (s_inputdcb[port].trg_mode[i] == 0) {
            s_inputdcb[port].trg_mode[i] = trigmode;
            s_inputdcb[port].c_inform[i] = informer;
            s_inputdcb[port].b_inform[i] = informer;
            s_inputdcb[port].ct_users++;
            return TRUE;
        }
    }

    SYS_ASSERT(false, RETURN_FALSE);
}


